#include "server.h"
#include "Mysql.h"

#define PORT 8080


const int LISTEN_NUM = 5;
string PATH_FILE = "/home/xjh/file_trancfer/recv";



class Mysql;
Mysql mysql; //实例一个数据库对象

void Server::server_Start(Mysql  sql){

  //1.启动数据库
  mysql = sql;
  cout << "creating sockfd..." << endl;
  
  //2.创建套接字
  _sockfd = creat_socket();

  //3.指令处理
  handle_message(_sockfd);
}


//列表展示
void Server::List_file(char* myargv[], int sock){ // buff为myargv，接收消息容器

  cout << "start list show : " << endl;
  cout << "sock : " << sock << endl;

  Mysql sql;
  char read_buff[1024] = {"Ok#"};
  char *str = nullptr;

  while((sql._row = mysql_fetch_row(sql._result))){
    for(int i = 0; i < sql._result->field_count; ++i){
      cout << sql._row[i] << endl;
      str = sql._row[i];
      cout << sql._row[i] << endl;
      strcat(read_buff, str);
      strcat(read_buff, "\n");
    }
    cout << endl;
  }
  send(sock, read_buff, strlen(read_buff), 0);
  cout << endl;
}

// download 文件
void Server::Send_file(char* myargv[], int sock){

  cout << "download sock: " << sock <<endl;
  cout << "name = " << myargv[1] << endl;

  char *name = myargv[1];
  char path_down[128] = "/home/xjh/file_transfer/recv";

  strcat(path_down, name);  //将下载下来的文件放在该目录下

  cout << "download file path is $: " << path_down << endl;


  //打开该文件
  int fd = open(path_down, O_RDONLY);

  if(fd == -1){
    cerr << "open file error..." << errno << endl;
    return;
  }

  //获取文件大小
  int size = lseek(fd, 0, SEEK_END); 

  //重置我们的文件指针到文件开始
  lseek(fd, 0, SEEK_SET);
  
  char buff[32] = {0};
  sprintf(buff, "ok#%d", size);
  send(sock, buff, strlen(buff), 0);

  if(size == 0){
    return ;
  }
  char status[32] = {0};
  if(recv(sock, status, 31, 0) <= 0){
    return ;
  }
  if(strcmp(status, "ok")){
    return ;
  }

  char send_buff[256] = {0};
  int len = 0;
  while((len = read(fd, send_buff, 256)) > 0){
    cout << "len = " << len << endl;
    send(sock, send_buff, len, 0);
  }

  close(fd);

  cout << "send finish!" << endl;
}

//上传文件到数据库
void Server::thread_receive_file(char* myargv[], int sock){ //上传文件到数据库
    cout << "name = " << myargv[1] << ", size = " << myargv[2] << endl;
    //char* name = myargv[1];

    char* name = myargv[1];
    PATH_FILE += name;

    cout << "file path: " << PATH_FILE << endl;

    auto size = atoi(myargv[2]);

    //打开文件
    int fd = open(PATH_FILE.c_str(), O_WRONLY|O_CREAT, 0777); 
    if(fd == -1){
      cerr << "open file error" << errno << endl;
      return ;
    }
      
    //打开成功，发送确认消息
    send(sock, "ok", 2, 0);
    
    char buff[1024] = {0};

    int num = 0;
    int recv_size = 0;
    int count = 0;
    while((num = recv(sock, buff, 1024, 0)) > 0){
      cout << buff << ": size = " << num << endl;

      char str[2] = "";
      str[0] = buff[0];
      str[1] = buff[1];

      //求线程数？？？
      int thread_id = atoi(str);
      cout << "thread_id : " << thread_id << endl;

      count++;

      // ????
      num -= 2;

      cout << buff << ",len = " << strlen(buff) << endl;
      recv_size += num;
      cout << "recv_size: " << recv_size << endl;
      
      int off = lseek(fd, thread_id*1000, SEEK_SET);
      cout << "偏移的字节数：" << off << endl; 

      //向buff中写入读到的数据
      write(fd, buff+2, strlen(buff)-2);
      memset(buff, 0, sizeof(buff));
      lseek(fd, 0, SEEK_SET);
      cout << "------------------------------------------------------------------\t\n";
      cout << "recv_size: " << recv_size << endl;
      if(recv_size >= size){
        break;
      }
    }

    //将读到的文件保存到数据库中
    mysql.AddFile(size, name);
    cout << "recv_total: " << recv_size << ",total size: " << size << endl;
    //关闭文件描述符
    close(fd);
}


//创建套接字
int Server::creat_socket(){
  int listen_sock = socket(AF_INET,SOCK_STREAM,0);

  if(listen_sock == -1){
    cerr << "sock create error: " << errno << endl;
    return -1;
  }

  int opt = 1;
  setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

  struct sockaddr_in local;
  memset(&local, 0, sizeof(local));
  local.sin_family = AF_INET;
  local.sin_port = htons(PORT);
  local.sin_addr.s_addr = htonl(INADDR_ANY);

  if(bind(listen_sock, (struct sockaddr*)&local, sizeof(local)) < 0){
    cerr << "bind socket error " << endl;
    exit(1);
  }

  if(listen(listen_sock,LISTEN_NUM) < 0){
    cerr << "listen error " << endl;
    exit(2);
  }

  cout << "start Listening..." << endl;
  return listen_sock;
}

//线程处理函数
void* thread_file(void* arg){
  Server ser;
  int sock = *(int *)arg;


  while(1){
    char buff[1024] = "";
    int size = recv(sock, buff, strlen(buff), 0);
    cout << "recv = " << buff << endl;
    cout << "sock id = " << sock << endl;

    if(size < 0){
      break;
    }else{
      //cout << "recv = " << buff << endl;
    }

    char* myargv[20] = {0};
    char* saveptr = nullptr;

    char* ptr = strtok_r(buff, " ", &saveptr);
    
    if(ptr == nullptr){
      continue;
    }

    myargv[0] = ptr; // 得到用户指令list,upload,download
    
    int i = 0;
    while(ptr != nullptr){
      myargv[i++] = ptr;
      ptr = strtok_r(nullptr, " ", &saveptr);
    }

    if(strcmp(ptr, "ls") == 0){
      cout << "show file list: " << endl;
      ser.List_file(myargv, sock);
    }
    else if(strcmp(ptr, "upload") == 0){
      cout << "start to upload..." << endl; 
      ser.thread_receive_file(myargv, sock);
    }
    else if(strcmp(ptr, "download") == 0){
      cout << "start to download..." << endl;
      ser.Send_file(myargv, sock);
    }
    else{
      break;
    }
  }
}

//一旦监听套接字成功，开始进行message_handle
void Server::handle_message(int sockfd){
  cout << "sockfd = %d\n " << sockfd;
  struct sockaddr_in peer;
  while(1){
    socklen_t len = sizeof(peer);
    int sock = accept(sockfd, (struct sockaddr*)&peer, &len);
    if(sock < 0){
      cerr << "accept error" << endl;
      continue;
    }
    cout << "accept client num: " << sock << endl;
    cout << "receive port: " << inet_ntoa(peer.sin_addr) << "\r\t";

    pthread_t pid; //创建线程来处理事件
    pthread_create(&pid, nullptr, thread_file, (void*)&sock);
  }
}

